package com.wzl.kgmusic;

import android.content.Context;
import android.content.pm.PackageManager;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Controller implements Runnable {
    private final int SIZE = 2048;
    private final int mMinSize;
    private Decoder mDecoderBanzou, mDecoderOrg;
    private boolean mIsOrg = false;
    private DataBuffer mDataBufferBanzou = new DataBuffer(40960);
    private DataBuffer mDataBufferOrg = new DataBuffer(40960);
    private Callback mCallback;
    private byte[] mBufferBanzou, mBufferOrg;
    private AudioTrack mAudioTrack;
    private boolean mIsStop;
    private int mPlaySize;
    private String mBanzouFilePath, mOrgFilePath, mRecFilePath;
    private FileThread mThread;

    public Controller(Context context, Callback callback, String banzouFilePath, String orgFilePath, String recFilePath) {

        mBanzouFilePath = banzouFilePath;
        mOrgFilePath = orgFilePath;
        mRecFilePath = recFilePath;
        boolean hasLowLatencyFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);
        boolean hasProFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_PRO);
        if (hasProFeature) {
            Constants.WAVE_DELAY_CUL = 20;
        } else if (hasLowLatencyFeature) {
            Constants.WAVE_DELAY_CUL = 45;
        } else {
            Constants.WAVE_DELAY_CUL = 65;
        }
        mPlaySize = 0;
        mCallback = callback;
        mBufferBanzou = new byte[SIZE];
        mBufferOrg = new byte[SIZE];
        if (mBanzouFilePath != null)
            mDecoderBanzou = new Decoder(context, mDataBufferBanzou, mBanzouFilePath);
        if (!TextUtils.isEmpty(mOrgFilePath))
            mDecoderOrg = new Decoder(context, mDataBufferOrg, mOrgFilePath);
        mMinSize = AudioTrack.getMinBufferSize(44100,
                AudioFormat.CHANNEL_OUT_STEREO,
                AudioFormat.ENCODING_PCM_16BIT);
        mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO,
                AudioFormat.ENCODING_PCM_16BIT, mMinSize, AudioTrack.MODE_STREAM);
        Constants.PLAY_DELAY += (int) (mMinSize / 176.4) * 2;
    }

    public void start() {
        if (mDecoderBanzou != null)
            mDecoderBanzou.startPlay();
        if (mDecoderOrg != null)
            mDecoderOrg.startPlay();
        mAudioTrack.play();
        mThread = new FileThread();
        mThread.start();
        new Thread(this).start();
    }

    public void destroy() {
        mIsStop = true;
    }

    public void openOriginalSinging(boolean isOrg) { //开启或关闭原唱
        mIsOrg = isOrg;
    }

    @Override
    public void run() {
        byte[] bf = new byte[SIZE];
        while (!mIsStop) {
            if (mDecoderBanzou != null) mDataBufferBanzou.getData(mBufferBanzou);
            boolean retOrg = false;
            if (mDecoderOrg != null)
                retOrg = mDataBufferOrg.getData(mBufferOrg);
            for (int i = 0; i < SIZE / 4; i++) {
                bf[i * 4 + 2] = bf[i * 4] = mBufferBanzou[i * 4];
                bf[i * 4 + 3] = bf[i * 4 + 1] = mBufferBanzou[i * 4 + 1];
            }
            if(mThread != null && mThread.mHandler != null){
                Message.obtain( mThread.mHandler, 1, bf.clone()).sendToTarget();
            }

            if (mIsOrg && retOrg) {
                bf = new byte[SIZE];
                for (int i = 0; i < SIZE / 4; i++) {
                    bf[i * 4 + 2] = bf[i * 4] = mBufferOrg[i * 4];
                    bf[i * 4 + 3] = bf[i * 4 + 1] = mBufferOrg[i * 4 + 1];
                }

            }
            mAudioTrack.write(bf, 0, SIZE);
            mPlaySize += SIZE;
            long time = (long) (1000f * mPlaySize / (44100 * 2 * 2)) - Constants.PLAY_DELAY;
            if (mCallback != null) {
                mCallback.onPlayerTime(time);
            }
        }
        releaseAll();
        if (mDecoderBanzou != null)
            mDecoderBanzou.stopPlay();
        if (mDecoderOrg != null)
            mDecoderOrg.stopPlay();
    }

    private void releaseAll() {
        Log.d("Controller", "releaseAll===");
        if (mAudioTrack != null) {
            AudioTrack mReleaseAudioTrack = mAudioTrack;
            mAudioTrack = null;
            mReleaseAudioTrack.stop();
            mReleaseAudioTrack.release();
        }
    }

    class FileThread extends Thread {
        public Handler mHandler;
        private FileOutputStream fos;

        @Override
        public void run() {
            super.run();
            try {
                fos = new FileOutputStream(mRecFilePath);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            Looper.prepare();
            mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    if (msg.what == -1) {
                        mHandler.getLooper().quit();
                    } else if (msg.what == 1) {
                        if (fos != null) {
                            try {
                                fos.write((byte[]) msg.obj);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            };
            Looper.loop();
            try {
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
